package com.imu.purse.modules.app.service.impl;

import com.alibaba.fastjson.JSON;
import com.github.pagehelper.PageHelper;
import com.imu.common.exception.RRException;
import com.imu.common.utils.IPUtils;
import com.imu.constant.Constant;
import com.imu.core.base.BaseService;
import com.imu.datasources.DataSourceNames;
import com.imu.datasources.annotation.DataSource;
import com.imu.purse.bean.CoreMoneyAddr;
import com.imu.purse.modules.app.dao.ImuUserIdentiryMapper;
import com.imu.purse.modules.app.dao.ImuUserInvMapper;
import com.imu.purse.modules.app.dao.ImuUserMapper;
import com.imu.purse.modules.app.entity.ImuUserEntity;
import com.imu.purse.modules.app.entity.ImuUserInvEntity;
import com.imu.purse.modules.app.form.RegisterForm;
import com.imu.purse.modules.app.service.ImuUserService;
import com.imu.purse.modules.bitcoin.YtfcoinApi;
import com.imu.purse.modules.trade.dao.FundMapper;
import com.imu.purse.modules.trade.dao.TradeInfoMapper;
import com.imu.purse.modules.trade.entity.FundEntity;
import com.imu.purse.modules.trade.entity.TradeInfoEntity;
import com.imu.utils.ShortUUID;
import com.qiniu.util.StringUtils;
import com.xiaoleilu.hutool.crypto.SecureUtil;
import com.xiaoleilu.hutool.date.DateUtil;
import com.xiaoleilu.hutool.util.ArrayUtil;
import com.xiaoleilu.hutool.util.NumberUtil;
import com.xiaoleilu.hutool.util.StrUtil;
import org.apache.commons.lang.RandomStringUtils;
import org.apache.poi.xssf.usermodel.XSSFCell;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.apache.shiro.crypto.hash.Sha256Hash;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.*;

/**
 * 用户信息
 * @author sunhongwei
 * @email sunhongwei@jshijian.com
 * @date 2018-03-21 10:11:22
 * Copyright (c) 2017 武汉极时间科技有限公司 版权所有 
 * Jshijian aloha CO.,LTD. All Rights Reserved. 
 */
@Service
public class ImuUserServiceImpl extends BaseService<ImuUserEntity> implements ImuUserService 
{
	@Override
    @Transactional
    public int save(ImuUserEntity imuUser,String userInvPhone)
	{
		imuUser.setTimeCreate(new Date());
    	imuUser.setTimeUpdate(new Date());
    	super.insert(imuUser); 

    	redisTemplate.opsForValue().set(imuUser.getPhone(), JSON.toJSONString(imuUser));

    	if(!StringUtils.isNullOrEmpty(userInvPhone)){
			//插入之后再处理邀请人表
			ImuUserInvEntity iuin = new ImuUserInvEntity();
			iuin.setUserId(imuUser.getId());
			iuin.setTimeCreate(new Date());
			iuin.setUserUpdate(imuUser.getId());

			String userStr = redisTemplate.opsForValue().get(userInvPhone);
			if(!StringUtils.isNullOrEmpty(userStr)){
				ImuUserEntity tmpUser = JSON.parseObject(userStr,ImuUserEntity.class);
				iuin.setUserInvId(tmpUser.getId());
			}
			imuUserInvMapper.insert(iuin);
    	}
    	return 1;
	}
	
	@Override
	@Transactional
    public int updatePhone(final ImuUserEntity imuUser) 
    {
		//userName存了修改之前的手机号
		String oldPhone = imuUser.getUserName();
		//更新之后之前的缓存数据不变，将新的手机号数据获取之后保存到数据库   但是身份宝手机号要修改
    	imuUser.setTimeUpdate(new Date());
    	imuUser.setUserName(imuUser.getPhone());
    	int i = mapper.updateByPrimaryKeySelective(imuUser);
    	//将新数据保存到缓存
    	String str = JSON.toJSONString(imuUser); 
    	redisTemplate.opsForValue().set(imuUser.getPhone(), str);
    	//修改redis之前的手机号的身份宝数据
    	Object QrCode = redisTemplate.opsForHash().get("googleQrCode", oldPhone);
    	//将现在的手机号更新进redis并删除之前redis
    	if(null != QrCode){//有可能没有绑定过身份认证消息
    		redisTemplate.opsForHash().put("googleQrCode", imuUser.getPhone(),QrCode);
        	redisTemplate.opsForHash().delete("googleQrCode", oldPhone);
        	//修改数据库的值
        	imuUserIdentiryMapper.updByUserId(imuUser.getId());
    	}
    	
    	return i;
    }
    
    @Override
	@Transactional
    public int saveUpdate(final ImuUserEntity imuUser)
    {
    	int len = 0;
    	
    	if(1 > (len = this.update(imuUser)))
    	{
        	len = this.insert(imuUser);
    	}
    	
    	return len;
    }
    
 	@Override
	@Transactional
    public boolean delete(final String ...ids)
    {
    	if(ArrayUtil.isEmpty(ids)) return false;
    	
    	for (String id : ids) 
    	{
    		if(StrUtil.isBlank(id)) continue;
    		
    		if(NumberUtil.isNumber(id))
    		{
        		mapper.deleteByPrimaryKey(Long.valueOf(id));
    		}
		}
    	
    	return true;
    }
    
    @Override
    @DataSource(name=DataSourceNames.SECOND)
    public ImuUserEntity findById(final Long id)
    {
    	if(null == id) return null;
    	return mapper.selectByPrimaryKey(id);
    }
    
    @Override
    public ImuUserEntity findCacheById(final Long id)
    {
    	if(null == id) return null;
    	
    	String key = Constant.SYS_USER;
		HashOperations<String, String, String> operations = redisTemplate.opsForHash();
    	String info = operations.get(key, String.valueOf(id));
    	ImuUserEntity entity = null;
    	
    	if(StrUtil.isBlank(info)){
    		if(null != (entity = this.findById(id)) && StrUtil.isNotBlank(entity.getPhone())){
    			operations.put(key, String.valueOf(id), JSON.toJSONString(entity));
    			return entity;
    		}
    		
    		return null;
    	}
    	
    	return JSON.parseObject(info, ImuUserEntity.class);
    }
    
    @Override
    @DataSource(name=DataSourceNames.SECOND)
    public List<ImuUserEntity> queryList(final ImuUserEntity imuUser)
    {
    	if (imuUser.getPage() != null && imuUser.getLimit() != null)
    	{
            PageHelper.startPage(imuUser.getPage(), imuUser.getLimit());
        }
    	
    	return mapper.findByPage(imuUser);
    }
    
	@Override
	public ImuUserEntity queryByMobile(String phone) {
		ImuUserEntity userEntity = new ImuUserEntity();
		userEntity.setPhone(phone);
		return mapper.selectOne(userEntity);
	}
	
	@Override
	public ImuUserEntity login(ImuUserEntity imuUser, String pwd) 
	{
		ImuUserEntity imuUsers = mapper.selectOne(imuUser);
		if(imuUsers == null || StrUtil.isBlank(pwd) || !imuUsers.getPwd().equals(new Sha256Hash(pwd, imuUsers.getSalt()).toHex()))
		{
			return null;
			//throw new RRException(ErrorDesc.PHONE_OR_PWD_REG.getMsg(), ErrorDesc.PHONE_OR_PWD_REG.getCode());
		}
		
		return imuUsers;
	}
	
	@Override
	@Transactional
	public int updates(ImuUserEntity entity) {
		// TODO Auto-generated method stub
		return mapper.updates(entity);
	}
	
	@Transactional
	public int registerUser(final RegisterForm form,final String moneyAddr){
		/**
		 * 以下是保存用户的
		 */
		ImuUserEntity user = new ImuUserEntity();
        user.setPhone(form.getPhone());
        user.setUserName(form.getPhone());
        String salt = RandomStringUtils.randomAlphanumeric(20);
        user.setPwd(new Sha256Hash(form.getPwd(), salt).toHex());
        user.setPayPwd(new Sha256Hash(form.getPayPwd()).toHex());
        user.setSalt(salt);
        user.setTimeCreate(new Date());
        save(user, form.getUserInvPhone());
        
        FundEntity fEntity = new FundEntity();
        fEntity.setUserId(user.getId());
        fEntity.setMoney(new BigDecimal(0));
        fEntity.setLockMoney(fEntity.getMoney());
        fEntity.setFrozenMoney(fEntity.getMoney());
        fEntity.setMoneyAddress(form.getMoneyAddress());
        fEntity.setTimeCreate(user.getTimeCreate());
        fundMapper.insert(fEntity);
		//将钱包地址和用户id绑定
		redisTemplate.opsForHash().put(Constant.CORE_MONEY_USER_KEY,fEntity.getMoneyAddress(),user.getId().toString());
		//将用户ID和核心钱包ip绑定
		redisTemplate.opsForHash().put(Constant.USER_CORE_MONEY_KEY,user.getId().toString(),moneyAddr);
        return 1;
        
	}
	/**
	 * 忘记密码同时忘记密钥
	 */
	@Override
	@Transactional
	public int updates(ImuUserEntity imuUser, Long userId) {
		mapper.updateByPrimaryKeySelective(imuUser);
		imuUserIdentiryMapper.updByUserId(userId);
		return 1;
	}
	
	@Override
	@Transactional
	public int saveFile(File file, HttpServletRequest request) {
		Map<String,Object> resultMap=new HashMap<String,Object>();
		//获取excel文件
		XSSFWorkbook xssfWorkbook;
		try {
			xssfWorkbook = new XSSFWorkbook(new FileInputStream(file));
			for (int numSheet = 0; numSheet < xssfWorkbook.getNumberOfSheets(); numSheet++) {
				XSSFSheet xssfSheet = xssfWorkbook.getSheetAt(numSheet);
				if (xssfSheet == null) {
					continue;
				}
				// Read the Row
				for (int rowNum = 1; rowNum <= xssfSheet.getLastRowNum(); rowNum++) {
					XSSFRow xssfRow = xssfSheet.getRow(rowNum);
					if (xssfRow != null) {
					//student = new Student();
					XSSFCell nickName = xssfRow.getCell(0);//昵称
					XSSFCell pwd = xssfRow.getCell(1);//密码(需要两次加密)
					XSSFCell cardNo = xssfRow.getCell(2);//身份证号
					XSSFCell money = xssfRow.getCell(3);//余额
					XSSFCell phone= xssfRow.getCell(4);//用户名或密码
					//XSSFCell phone = xssfRow.getCell(6);//钱包地址  需要自己生成替换
					if (null==phone || phone.toString().length()<=1) {
						return 1;
					}

					Double phones=Double.parseDouble(getValue(phone));
					BigDecimal bd1 = new BigDecimal(phones);
					String myPhone=bd1.toPlainString();
					//随机选择核心钱包
					CoreMoneyAddr moneyAddr = initCoreMoneyAddr();
					String moneyAddrStr = JSON.toJSONString(moneyAddr);
					/***
					 * 以下是校验该用户是否存在钱包中，不存在的话则需要注册
					 * 1、校验钱包服务器是否存在
					 * 2、校验该手机号码是否存在
					 * 3、如果存在多个话则取第一个，如果不存在，则获取新的地址
					 */
					String nAddress = ytfcoinApi.createAccount(myPhone,moneyAddrStr);
					if(StringUtils.isNullOrEmpty(nAddress)){
						log.error("phone : " + phone + " create core money address error");
						return 1;
					}
					//1.添加用户信息与资金信息
					ImuUserEntity iue = new ImuUserEntity();
					iue.setPhone(myPhone);

					if(null != mapper.selectOne(iue)){
						continue;
					}
					iue.setNickName(getValue(nickName));
					iue.setUserName(myPhone);
					iue.setPhone(myPhone);
					iue.setIdentCode(getValue(cardNo));
					iue.setState(1);
					iue.setTimeCreate(new Date());
					String secret = SecureUtil.md5(getValue(pwd));
					String salt = RandomStringUtils.randomAlphanumeric(20);
					iue.setPwd(new Sha256Hash(secret, salt).toHex());//密码盐加密
					iue.setPayPwd(new Sha256Hash(secret).toHex());//支付密码不盐加密
					iue.setSalt(salt);
					super.insert(iue); 
			    	String str = JSON.toJSONString(iue); 
			    	redisTemplate.opsForValue().set(iue.getPhone(), str);
					

					
					FundEntity fund = new FundEntity();
					fund.setUserId(iue.getId());
					fund.setMoney(new BigDecimal(0));
					fund.setTimeCreate(new Date());
					fund.setMoneyAddress(nAddress);
					fund.setLockMoney(new BigDecimal(0));
					fund.setFrozenMoney(new BigDecimal(0));
					String ipStr = IPUtils.getLocalAddress();
					fund.setPassword(ipStr == null ? ShortUUID.UUID() : ipStr + ShortUUID.UUID());
					fundMapper.insert(fund);
					//将钱包地址和用户id绑定
					redisTemplate.opsForHash().put(Constant.CORE_MONEY_USER_KEY,fund.getMoneyAddress(),iue.getId().toString());
					//将用户ID和核心钱包ip绑定
					redisTemplate.opsForHash().put(Constant.USER_CORE_MONEY_KEY,iue.getId().toString(),moneyAddrStr);
					
					}
				}
			}
		} catch (IOException e) {
			// TODO Auto-generated catch block
			throw new RRException("上传失败", e);
		}
		return 1;
	}
	
	/**
     * 选择核心钱包
     * @return
     */
    private CoreMoneyAddr initCoreMoneyAddr(){
        //随机获取核心钱包的服务器
        //获取所有的核心钱包的地址
        List<String> coreList = redisTemplate.opsForList().range(Constant.CORE_MONEY_KEY,0,-1);
        //随机取一个核心钱包的地址
        Random rand = new Random();
        int curSel = rand.nextInt(coreList.size());
        String selAddr = coreList.get(curSel);
        CoreMoneyAddr moneyAddr = JSON.parseObject(selAddr, CoreMoneyAddr.class);

        return moneyAddr;
    }
	private String getValue(XSSFCell nickName) {
		// TODO Auto-generated method stub
		return nickName != null ? nickName.toString() : null;
	}
	
	@Override
	@Transactional
    public int update(final ImuUserEntity imuUser) 
    {
    	int i = mapper.updateByPrimaryKeySelective(imuUser);
    	//根据用户ID获取该用户的金额
		ImuUserEntity imuUserEntity = mapper.selectByPrimaryKey(imuUser);
		redisTemplate.opsForValue().set(imuUserEntity.getPhone(),JSON.toJSONString(imuUserEntity));
    	return i;
    }

	@Override
	@Transactional
	public int updateByPhone(final ImuUserEntity imuUser)
	{
		int i = mapper.updateByPhone(imuUser);
		//根据用户ID获取该用户的金额
		ImuUserEntity imuUserEntity = mapper.selectUserInfoByPhone(imuUser.getPhone());
		redisTemplate.opsForValue().set(imuUserEntity.getPhone(),JSON.toJSONString(imuUserEntity));
		return i;
	}

	@Override
	public FundEntity showUserMoney(long uid) {
		
		return fundMapper.findByUserId(uid); 
	}
	/**
	 * 内部转账完成之后修改转出人与转账人信息   以及插入交易信息
	 */
	@Override
	@Transactional
	public int transaction(ImuUserEntity imuOutPerson, ImuUserEntity imuInPerson, String money, int status,
						   BigDecimal fee,String transId) {
		Date nowDate = new Date();
		BigDecimal big = new BigDecimal(money);

		if(status==0){//不同钱包内转账

			FundEntity fund = new FundEntity();
			fund.setUserId(imuOutPerson.getId());
			fund.setMoney(big);
			fund.setTimeUpdate(new Date());
			fundMapper.reduceMoney(fund);
			//接收人信息
			fund.setUserId(imuInPerson.getId());
			fundMapper.addMoney(fund);
		}else { //同一个钱包内部转账
			FundEntity fund = new FundEntity();
			fund.setUserId(imuOutPerson.getId());
			fund.setFrozenMoney(big.add(fee));
			fundMapper.moFrozenMoney(fund);
			
		}
		TradeInfoEntity tradeInfo = new TradeInfoEntity();
		tradeInfo.setPayUserId(imuOutPerson.getId());
		tradeInfo.setRecUserId(imuInPerson.getId());
		tradeInfo.setTransId(transId);
		tradeInfo.setOrderType(0);
		tradeInfo.setOrderState(0);
		if(status==0){
			tradeInfo.setOrderState(1);
		}
		tradeInfo.setMoney(big);
		tradeInfo.setOrderCreate(new Date());
		tradeInfo.setRecAddr(imuInPerson.getAddress());
		tradeInfo.setRecPhone(imuInPerson.getPhone());

		tradeInfo.setFee(fee);
		tradeInfo.setOrderNo(DateUtil.format(nowDate, "yyyyMMddHHmmssSSS"));

		tradeInfoMapper.insert(tradeInfo);
		tradeInfo = new TradeInfoEntity();
		tradeInfo.setPayUserId(imuInPerson.getId());
		tradeInfo.setRecUserId(imuOutPerson.getId());
		tradeInfo.setTransId(transId);
		tradeInfo.setOrderType(2);
		tradeInfo.setOrderState(0);

		if(status==0){
			tradeInfo.setOrderState(1);
		}
		tradeInfo.setMoney(big);
		tradeInfo.setOrderCreate(new Date());
		tradeInfo.setRecAddr(imuOutPerson.getAddress());
		tradeInfo.setRecPhone(imuOutPerson.getPhone());

		tradeInfo.setFee(fee);
		tradeInfo.setOrderNo(DateUtil.format(nowDate, "yyyyMMddHHmmssSSS"));

		tradeInfoMapper.insert(tradeInfo);
		return 1;
	}

	/**
	 * 修改用户接受手机短信手机号码
	 * @param entity
	 * @return
	 */
	public int concatPhone(final ImuUserEntity entity){
		entity.setPhone(null);
		this.update(entity);

		return 1;
	}

	public ImuUserEntity findUserByPhone(String phone){
		ImuUserEntity userEntity = null;
		String userStr = redisTemplate.opsForValue().get(phone);
		if(StrUtil.isNotEmpty(userStr)){
			userEntity = JSON.parseObject(userStr,ImuUserEntity.class);
			return userEntity;
		}
		//从数据库查询
		userEntity = new ImuUserEntity();
		userEntity.setPhone(phone);
		userEntity = mapper.selectOne(userEntity);
		if(userEntity != null){
			redisTemplate.opsForValue().set(phone,JSON.toJSONString(userEntity));
			return userEntity;
		}
		return userEntity;
	}
	@Autowired
	private ImuUserMapper mapper;
	
	@Autowired
	private ImuUserInvMapper imuUserInvMapper;
	
	@Autowired
	private FundMapper fundMapper;
	
	@Autowired
    private RedisTemplate<String, String> redisTemplate;
	
	@Autowired
    private YtfcoinApi ytfcoinApi;
	
	@Autowired
	private ImuUserIdentiryMapper imuUserIdentiryMapper;
	
	@Autowired
	private TradeInfoMapper tradeInfoMapper;

	private static Logger log = LoggerFactory.getLogger(ImuUserService.class);

}
